package com.wanghaicheng.util;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;

/**
 * POIFS (较差混淆技术实现文件系统): 此组件是所有其他POI元件的基本因素。它被用来明确地读取不同的文件。
 * HSSF (可怕的电子表格格式): 它被用来读取和写入MS-Excel文件的xls格式。
 * XSSF (XML格式): 它是用于MS-Excel中XLSX文件格式。
 * HPSF (可怕的属性设置格式): 它用来提取MS-Office文件属性设置。
 * HWPF (可怕的字处理器格式): 它是用来读取和写入MS-Word的文档扩展名的文件。
 * XWPF (XML字处理器格式): 它是用来读取和写入MS-Word的docx扩展名的文件。
 * HSLF (可怕的幻灯片版式格式): 它是用于读取，创建和编辑PowerPoint演示文稿。
 * HDGF (可怕的图表格式): 它包含类和方法为MS-Visio的二进制文件。
 * HPBF (可怕的出版商格式): 它被用来读取和写入MS-Publisher文件。//原文出自【易百教程】，商业转载请联系作者获得授权，非商业请保留原文链接：https://www.yiibai.com/apache_poi/
 */
public class WordUtil implements Office {
    /**
     * 从文件加载文档
     */
    public static XWPFDocument loadDocumentFromFile(String filePath) {
        try {
            return new XWPFDocument(new FileInputStream(filePath));
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("无法加载文档: " + e.getMessage());
        }
    }

    /**
     * 从网络URL加载文档
     */
    public static XWPFDocument loadDocumentFromUrl(String urlStr) throws IOException {
        URL url = new URL(urlStr);
        URLConnection connection = url.openConnection();
        connection.setConnectTimeout(5000);
        connection.setReadTimeout(10000);
        return new XWPFDocument(connection.getInputStream());
    }

    /**
     * 保存文档到文件
     */
    public static void saveDocument(XWPFDocument document, String outputPath) throws IOException {
        try (FileOutputStream out = new FileOutputStream(outputPath)) {
            document.write(out);
        }
    }

    /**
     * 替换文本占位符（支持段落和表格）
     */
    public static void replacePlaceholder(XWPFDocument document, String placeholder, String replacement) {
        // 处理段落中的占位符
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            replacePlaceholderInParagraph(paragraph, placeholder, replacement);
        }

        // 处理表格中的占位符
        for (XWPFTable table : document.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph paragraph : cell.getParagraphs()) {
                        replacePlaceholderInParagraph(paragraph, placeholder, replacement);
                    }
                }
            }
        }
    }

    /**
     * 批量替换文本占位符
     */
    public static void replacePlaceholders(XWPFDocument document, Map<String, String> placeholders) {
        placeholders.forEach((key, value) -> replacePlaceholder(document, key, value));
    }

    /**
     * 在段落中替换占位符
     */
    private static void replacePlaceholderInParagraph(XWPFParagraph paragraph, String placeholder, String replacement) {
        // 先构建整个段落的文本
        StringBuilder paragraphText = new StringBuilder();
        for (XWPFRun run : paragraph.getRuns()) {
            String text = run.getText(0);
            if (text != null) {
                paragraphText.append(text);
            }
        }

        String fullText = paragraphText.toString();
        if (fullText.contains(placeholder)) {
            // 清空所有运行
            for (int i = paragraph.getRuns().size() - 1; i >= 0; i--) {
                paragraph.removeRun(i);
            }

            // 创建新的运行
            XWPFRun newRun = paragraph.createRun();

            if (replacement.contains("\n")) {
                String[] lines = replacement.split("\n");

                // 第一行直接设置
                newRun.setText(lines[0]);

                // 后续行添加换行和制表符来保持缩进
                for (int i = 1; i < lines.length; i++) {
                    newRun.addBreak();
                    // 添加固定数量的制表符（通常1-2个）
                    newRun.addTab(); // 第一个制表符用于基本缩进
                    newRun.addTab(); // 第二个制表符用于额外缩进（可选）
                    newRun.setText(lines[i]);
                }
            } else {
                newRun.setText(fullText.replace(placeholder, replacement));
            }
        }
    }

    /**
     * 处理表格动态数据
     */
    public static void processTableData(XWPFDocument document, int tableIndex, int templateRowIndex,
                                        List<Map<String, String>> dataList) {
        if (tableIndex < 0 || tableIndex >= document.getTables().size()) {
            throw new IllegalArgumentException("无效的表格索引: " + tableIndex);
        }

        XWPFTable table = document.getTables().get(tableIndex);

        if (templateRowIndex < 0 || templateRowIndex >= table.getRows().size()) {
            throw new IllegalArgumentException("无效的模板行索引: " + templateRowIndex);
        }

        // 获取模板行
        XWPFTableRow templateRow = table.getRow(templateRowIndex);

        // 为每个数据项创建新行
        for (Map<String, String> data : dataList) {
            // 复制模板行
            XWPFTableRow newRow = table.insertNewTableRow(templateRowIndex + 1);
            copyRowContent(templateRow, newRow);

            // 替换新行中的占位符
            for (XWPFTableCell cell : newRow.getTableCells()) {
                for (XWPFParagraph paragraph : cell.getParagraphs()) {
                    for (Map.Entry<String, String> entry : data.entrySet()) {
                        replacePlaceholderInParagraph(paragraph, entry.getKey(), entry.getValue());
                    }
                }
            }
        }

        // 删除模板行
        table.removeRow(templateRowIndex);
    }

    /**
     * 复制行内容（保留样式）
     */
    private static void copyRowContent(XWPFTableRow sourceRow, XWPFTableRow targetRow) {
        // 确保目标行有足够的单元格
        while (targetRow.getTableCells().size() < sourceRow.getTableCells().size()) {
            targetRow.addNewTableCell();
        }

        // 复制每个单元格的内容和样式
        for (int i = 0; i < sourceRow.getTableCells().size(); i++) {
            XWPFTableCell sourceCell = sourceRow.getTableCells().get(i);
            XWPFTableCell targetCell = targetRow.getTableCells().get(i);

            // 清空目标单元格内容（保留样式）
            clearCellContent(targetCell);

            // 复制源单元格的段落到目标单元格
            for (XWPFParagraph para : sourceCell.getParagraphs()) {
                XWPFParagraph newPara = targetCell.addParagraph();
                copyParagraphContent(para, newPara);
            }

            // 复制单元格属性（宽度、颜色等）
            CTTc sourceTc = sourceCell.getCTTc();
            CTTc targetTc = targetCell.getCTTc();
            if (sourceTc.getTcPr() != null) {
                targetTc.setTcPr(sourceTc.getTcPr());
            }
        }

        // 复制行属性（高度等）
        if (sourceRow.getCtRow() != null && sourceRow.getCtRow().getTrPr() != null) {
            targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());
        }
    }

    /**
     * 清空单元格内容（保留样式）
     */
    private static void clearCellContent(XWPFTableCell cell) {
        // 移除所有现有段落
        for (int i = cell.getParagraphs().size() - 1; i >= 0; i--) {
            cell.removeParagraph(i);
        }
    }

    /**
     * 复制段落内容（保留样式）
     */
    private static void copyParagraphContent(XWPFParagraph source, XWPFParagraph target) {
        // 复制段落样式
        if (source.getCTP() != null && source.getCTP().getPPr() != null) {
            target.getCTP().setPPr(source.getCTP().getPPr());
        }

        // 复制文本片段
        for (XWPFRun run : source.getRuns()) {
            XWPFRun newRun = target.createRun();
            newRun.setText(run.getText(0));
            if (run.getStyle() != null) {
                newRun.setStyle(run.getStyle());
            }
            // 复制更多样式
            newRun.setBold(run.isBold());
            newRun.setItalic(run.isItalic());
            newRun.setFontFamily(run.getFontFamily());
            newRun.setFontSize(run.getFontSize());
            if (run.getColor() != null) {
                newRun.setColor(run.getColor());
            }
            newRun.setUnderline(run.getUnderline());
            newRun.setStrikeThrough(run.isStrikeThrough());
            newRun.setCharacterSpacing(run.getCharacterSpacing());
        }
    }

    /**
     * 替换图片占位符
     */
    public static void replaceImage(XWPFDocument document, String placeholder, String imagePath,
                                    int width, int height) throws IOException, InvalidFormatException {
        // 校验图片文件是否存在（本地路径时）
        if (imagePath != null && !"".equals(imagePath) && !imagePath.startsWith("http")) {
            File imageFile = new File(imagePath);
            if (!imageFile.exists() || !imageFile.isFile()) {
                throw new IOException("图片文件不存在: " + imagePath);
            }
        }

        // 处理段落中的图片占位符
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            if (paragraph.getText().contains(placeholder)) {
                replaceParagraphWithImage(paragraph, placeholder, imagePath, width, height);
            }
        }

        // 处理表格中的图片占位符
        for (XWPFTable table : document.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph paragraph : cell.getParagraphs()) {
                        if (paragraph.getText().contains(placeholder)) {
                            replaceParagraphWithImage(paragraph, placeholder, imagePath, width, height);
                        }
                    }
                }
            }
        }
    }

    /**
     * 替换段落中的占位符为图片
     */
    private static void replaceParagraphWithImage(XWPFParagraph paragraph,
                                                  String placeholder, String imagePath,
                                                  int width, int height) throws IOException, InvalidFormatException {
        // 移除占位符文本
        for (XWPFRun run : paragraph.getRuns()) {
            String text = run.getText(0);
            if (text != null && text.contains(placeholder)) {
                text = text.replace(placeholder, "");
                run.setText(text, 0);
            }
        }

        // 获取图片输入流
        try (InputStream is = getImageInputStream(imagePath)) {
            XWPFRun run = paragraph.createRun();
            String fileExt = getFileExtension(imagePath);
            int pictureType = getPictureType(fileExt);

//            if (pictureType == -1)
//            {
//                throw new IllegalArgumentException("不支持的图片类型: " + fileExt);
//            }

            // 转换像素为EMU单位
            run.addPicture(is, pictureType, imagePath,
                    Units.toEMU(width),
                    Units.toEMU(height));
        }
    }

    /**
     * 获取图片输入流（支持本地文件和网络URL）
     */
    private static InputStream getImageInputStream(String imagePath) throws IOException {
        if (imagePath != null && !"".equals(imagePath)) {
            return null;
        }
        if (imagePath.startsWith("http://") || imagePath.startsWith("https://")) {
            // 网络图片
            URL url = new URL(imagePath);
            URLConnection connection = url.openConnection();
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(10000);
            return connection.getInputStream();
        } else {
            // 本地图片
            return new FileInputStream(imagePath);
        }
    }

    /**
     * 获取文件扩展名
     */
    private static String getFileExtension(String filePath) {
        if (filePath == null || !filePath.contains(".")) {
            return "";
        }
        return filePath.substring(filePath.lastIndexOf(".") + 1).toLowerCase();
    }

    /**
     * 获取图片类型对应的POI常量
     */
    private static int getPictureType(String fileExt) {
        switch (fileExt) {
            case "jpg":
            case "jpeg":
                return XWPFDocument.PICTURE_TYPE_JPEG;
            case "png":
                return XWPFDocument.PICTURE_TYPE_PNG;
            case "gif":
                return XWPFDocument.PICTURE_TYPE_GIF;
            case "bmp":
                return XWPFDocument.PICTURE_TYPE_BMP;
            case "wmf":
                return XWPFDocument.PICTURE_TYPE_WMF;
            case "emf":
                return XWPFDocument.PICTURE_TYPE_EMF;
            case "pict":
                return XWPFDocument.PICTURE_TYPE_PICT;
            default:
                return -1;
        }
    }

    // ==================== 项目档案模板生成 ====================

    /**
     * 生成项目档案文档
     *
     * @param templateUrl      模板URL
     * @param textPlaceholders 文本占位符映射
     * @param traineeList      学员列表数据
     * @param images           图片替换信息列表
     * @param outputPath       输出路径
     */
    public static void generateProjectDocument(String templateUrl,
                                               Map<String, String> textPlaceholders,
                                               List<Map<String, String>> traineeList,
                                               Map<String, String> images,
                                               String outputPath) {
        try {
            XWPFDocument document = loadDocumentFromUrl(templateUrl);

            // 替换文本占位符
            replacePlaceholders(document, textPlaceholders);

            // 处理表格数据
            processTableData(document, 0, 10, traineeList);


            images.forEach((placeholder, path) -> {
                try {
                    replaceImage(document, placeholder, path, 100, 100);
                } catch (IOException | InvalidFormatException e) {
                    e.printStackTrace();
                }
            });

            // 保存文档
            saveDocument(document, outputPath);
            System.out.println("项目档案文档生成成功：" + outputPath);

        } catch (Exception e) {
            System.err.println("项目档案文档生成失败：" + e.getMessage());
            e.printStackTrace();
        }
    }


    public static void merged(Sheet sheet, int startRow, int lastRow, int startCol, int lastCol) {
        sheet.addMergedRegion(new CellRangeAddress(
                startRow,    // 起始行索引（从0开始）
                lastRow,     // 结束行索引
                startCol,    // 起始列索引（从0开始）
                lastCol      // 结束列索引
        ));
    }
}
